#ifndef REQUESTDATA_H_
#define REQUESTDATA_H_

#include <s32mem.h>

#include "scatu/utils.h"

namespace scatu {

class RRequestData0
    {
public:
    
    template<typename Class, typename ReturnType>
    struct MemFunWithArgs
        {
        typedef ReturnType (Class::*FuncPtr) ();
        static ReturnType CallL(Class & aObj, FuncPtr aFunc, RRequestData0 const & aArgs)
            { return (aObj.*aFunc)(); }
        
        typedef void (Class::*VoidFuncPtr) (MFunctor<ReturnType> &);
        static void CallL(Class & aObj, VoidFuncPtr aFunc, RRequestData0 const & aArgs,
                MFunctor<ReturnType> & aRetFunc)
            { return (aObj.*aFunc)(aRetFunc); }
        };
    
    RRequestData0() {}
    void Close() {}
    
    HBufC8* SerializeL() const { return HBufC8::NewL(0); }
    void DeserializeL(TDesC8 const & /*data*/) {}
    
    // Specials for 1 and 0 data
    typedef void ReturnType;
    enum { IsAssignable = false };  
    };


template<typename T1>
class RRequestData1
    {
public:
    template<typename Class, typename ReturnType>
    struct MemFunWithArgs
        {
        typedef ReturnType (Class::*FuncPtr) (typename RDataAdapter<T1>::ArgType);
        static ReturnType CallL(Class & aObj, FuncPtr aFunc, RRequestData1 const & aArgs)
            { return (aObj.*aFunc)(aArgs.iData1); }
        
        typedef void (Class::*VoidFuncPtr) (MFunctor<ReturnType> &,
                                            typename RDataAdapter<T1>::ArgType);
        static void CallL(Class & aObj, VoidFuncPtr aFunc, RRequestData1 const & aArgs,
                MFunctor<ReturnType> & aRetFunc)
            { return (aObj.*aFunc)(aRetFunc, aArgs.iData1); }
        };
    
    // Only for 1 and 0 data
    typedef typename RDataAdapter<T1>::ReturnType ReturnType;
    enum { IsAssignable = true };
    RRequestData1 & operator=(ReturnType aData)
        { iData1 = aData; }
    RDataAdapter<T1> & Data() { return iData1; }
    // END Only for 1 and 0 data
    
    RRequestData1() {}
    RRequestData1(typename RDataAdapter<T1>::ArgType aData1)
      : iData1(aData1) {}
    // TReturnTypeDesignator avoids ambiguous calls to constructor
    // (this is a bit ugly, but only used internally)
    RRequestData1(ReturnType aData1, TReturnTypeDesignator)
      : iData1(aData1) {}
    
    void Close()
        {
        iData1.Close();
        }
    
    HBufC8* SerializeL() const
        {
        RStreamWriteHelper streamHelper;
        CleanupClosePushL(streamHelper);
        
        RBufWriteStream & stream = streamHelper.OpenStreamL();
        stream << iData1;
        HBufC8 * ret = streamHelper.FinalizeStreamL();
        
        CleanupStack::PopAndDestroy(&streamHelper);
        return ret;
        }
    
    void DeserializeL(TDesC8 const & data)
        {
        RDesReadStream stream(data);
        CleanupClosePushL(stream);
        stream >> iData1;
        CleanupStack::PopAndDestroy(&stream);
        }

private:
    RDataAdapter<T1> iData1;

    };

template<typename T1, typename T2>
class RRequestData2
    {
public:
    
    template<typename Class, typename ReturnType>
    struct MemFunWithArgs
        {
        typedef ReturnType (Class::*FuncPtr) (typename RDataAdapter<T1>::ArgType,
                                              typename RDataAdapter<T2>::ArgType);
        static ReturnType CallL(Class & aObj, FuncPtr aFunc, RRequestData2 const & aArgs)
            { return (aObj.*aFunc)(aArgs.iData1, aArgs.iData2); }
        
        typedef void (Class::*VoidFuncPtr) (MFunctor<ReturnType> &,
                                            typename RDataAdapter<T1>::ArgType,
                                            typename RDataAdapter<T2>::ArgType);
        static void CallL(Class & aObj, VoidFuncPtr aFunc, RRequestData2 const & aArgs,
                MFunctor<ReturnType> & aRetFunc)
            { return (aObj.*aFunc)(aRetFunc, aArgs.iData1, aArgs.iData2); }
        };
    
    RRequestData2() {}
    RRequestData2(typename RDataAdapter<T1>::ArgType aData1,
                  typename RDataAdapter<T2>::ArgType aData2)
      : iData1(aData1), iData2(aData2) {}
    
    void Close()
        {
        iData1.Close();
        iData2.Close();
        }
    
    HBufC8* SerializeL() const
        {
        RStreamWriteHelper streamHelper;
        CleanupClosePushL(streamHelper);
        
        RBufWriteStream & stream = streamHelper.OpenStreamL();
        stream << iData1;
        stream << iData2;
        HBufC8 * ret = streamHelper.FinalizeStreamL();
        
        CleanupStack::PopAndDestroy(&streamHelper);
        return ret;
        }
    
    void DeserializeL(TDesC8 const & data)
        {
        RDesReadStream stream(data);
        CleanupClosePushL(stream);
        stream >> iData1;
        stream >> iData2;
        CleanupStack::PopAndDestroy(&stream);
        }

private:
    RDataAdapter<T1> iData1;
    RDataAdapter<T2> iData2;
    };

template<typename T1, typename T2, typename T3>
class RRequestData3
    {
public:
    
    template<typename Class, typename ReturnType>
    struct MemFunWithArgs
        {
        typedef ReturnType (Class::*FuncPtr) (typename RDataAdapter<T1>::ArgType,
                                              typename RDataAdapter<T2>::ArgType,
                                              typename RDataAdapter<T3>::ArgType);
        static ReturnType CallL(Class & aObj, FuncPtr aFunc, RRequestData3 const & aArgs)
            { return (aObj.*aFunc)(aArgs.iData1, aArgs.iData2, aArgs.iData3); }
        
        typedef void (Class::*VoidFuncPtr) (MFunctor<ReturnType> &,
                                            typename RDataAdapter<T1>::ArgType,
                                            typename RDataAdapter<T2>::ArgType,
                                            typename RDataAdapter<T3>::ArgType);
        static void CallL(Class & aObj, VoidFuncPtr aFunc, RRequestData3 const & aArgs,
                MFunctor<ReturnType> & aRetFunc)
            { return (aObj.*aFunc)(aRetFunc, aArgs.iData1, aArgs.iData2, aArgs.iData3); }
        };
    
    RRequestData3() {}
    RRequestData3(typename RDataAdapter<T1>::ArgType aData1,
                  typename RDataAdapter<T2>::ArgType aData2,
                  typename RDataAdapter<T3>::ArgType aData3)
      : iData1(aData1), iData2(aData2), iData3(aData3) {}
    
    void Close()
        {
        iData1.Close();
        iData2.Close();
        iData3.Close();
        }
    
    HBufC8* SerializeL() const
        {
        RStreamWriteHelper streamHelper;
        CleanupClosePushL(streamHelper);
        
        RBufWriteStream & stream = streamHelper.OpenStreamL();
        stream << iData1;
        stream << iData2;
        stream << iData3;
        HBufC8 * ret = streamHelper.FinalizeStreamL();
        
        CleanupStack::PopAndDestroy(&streamHelper);
        return ret;
        }
    
    void DeserializeL(TDesC8 const & data)
        {
        RDesReadStream stream(data);
        CleanupClosePushL(stream);
        stream >> iData1;
        stream >> iData2;
        stream >> iData3;
        CleanupStack::PopAndDestroy(&stream);
        }

private:
    RDataAdapter<T1> iData1;
    RDataAdapter<T2> iData2;
    RDataAdapter<T3> iData3;
    };

template<typename T1, typename T2, typename T3, typename T4>
class RRequestData4
    {
public:
    
    template<typename Class, typename ReturnType>
    struct MemFunWithArgs
        {
        typedef ReturnType (Class::*FuncPtr) (typename RDataAdapter<T1>::ArgType,
                                              typename RDataAdapter<T2>::ArgType,
                                              typename RDataAdapter<T3>::ArgType,
                                              typename RDataAdapter<T4>::ArgType);
        static ReturnType CallL(Class & aObj, FuncPtr aFunc, RRequestData4 const & aArgs)
            { return (aObj.*aFunc)(aArgs.iData1, aArgs.iData2, aArgs.iData3, aArgs.iData4); }
        
        typedef void (Class::*VoidFuncPtr) (MFunctor<ReturnType> &,
                                            typename RDataAdapter<T1>::ArgType,
                                            typename RDataAdapter<T2>::ArgType,
                                            typename RDataAdapter<T3>::ArgType,
                                            typename RDataAdapter<T4>::ArgType);
        static void CallL(Class & aObj, VoidFuncPtr aFunc, RRequestData4 const & aArgs,
                MFunctor<ReturnType> & aRetFunc)
            { return (aObj.*aFunc)(aRetFunc, aArgs.iData1, aArgs.iData2, aArgs.iData3, aArgs.iData4); }
        };
    
    RRequestData4() {}
    RRequestData4(typename RDataAdapter<T1>::ArgType aData1,
                  typename RDataAdapter<T2>::ArgType aData2,
                  typename RDataAdapter<T3>::ArgType aData3,
                  typename RDataAdapter<T4>::ArgType aData4)
      : iData1(aData1), iData2(aData2), iData3(aData3), iData4(aData4) {}
    
    void Close()
        {
        iData1.Close();
        iData2.Close();
        iData3.Close();
        iData4.Close();
        }
    
    HBufC8* SerializeL() const
        {
        RStreamWriteHelper streamHelper;
        CleanupClosePushL(streamHelper);
        
        RBufWriteStream & stream = streamHelper.OpenStreamL();
        stream << iData1;
        stream << iData2;
        stream << iData3;
        stream << iData4;
        HBufC8 * ret = streamHelper.FinalizeStreamL();
        
        CleanupStack::PopAndDestroy(&streamHelper);
        return ret;
        }
    
    void DeserializeL(TDesC8 const & data)
        {
        RDesReadStream stream(data);
        CleanupClosePushL(stream);
        stream >> iData1;
        stream >> iData2;
        stream >> iData3;
        stream >> iData4;
        CleanupStack::PopAndDestroy(&stream);
        }

private:
    RDataAdapter<T1> iData1;
    RDataAdapter<T2> iData2;
    RDataAdapter<T3> iData3;
    RDataAdapter<T4> iData4;
    };


} // namespace scatu

#endif /* REQUESTDATA_H_ */
